package com.daiziru.controller;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.daiziru.VO.CommentVO;
import com.daiziru.VO.PostVO;
import com.daiziru.common.Result;
import com.daiziru.common.constant.RedisConstants;
import com.daiziru.config.RabbitConfig;
import com.daiziru.entity.*;
import com.daiziru.search.mq.PostMqIndexMessage;
import com.daiziru.util.RedisUtil;
import com.daiziru.util.ValidationUtil;
import com.hazelcast.collection.impl.collection.CollectionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Date;

/**
 * 作者：無言
 * 时间：2022/12/7 0:54
 * 描述：永无BUG
 */
@Controller
public class PostController extends BaseController{

    @Autowired
    RedisUtil redisUtil;

    @Autowired
    RedisTemplate redisTemplate;


    @GetMapping("/category/{id:\\d*}") //指定接收的id为数字类型
    public String category(@PathVariable("id") Long id){
        int currentPage = ServletRequestUtils.getIntParameter(req,"currentPage", 1);
        req.setAttribute("currentCategoryId", id);
        req.setAttribute("currentPage", currentPage);
        return "post/category";
    }

    /**
     * 贴子详情
     * @param id 当前贴子的主键id
     * @return
     */
    @GetMapping("/postDetail/{id:\\d*}") //指定接收的id为数字类型
    public String detail(@PathVariable("id") Long id){
        //1、当前贴子详情
        PostVO vo = postService.selectOnePost(new QueryWrapper<MPost>().eq("p.id",id));
        Assert.notNull(vo, "文章已被删除！");

        //阅读量缓存设置
        postService.putViewCount(vo);

        //3、贴子评论信息查询
        //1分页 2文章id 3用户id 4排序类型
        IPage<CommentVO> comments =  commentService.selectCommentByPage(getPage(), vo.getId(), null, "created");

        req.setAttribute("currentCategoryId", vo.getCategoryId());
        req.setAttribute("postDetail",vo);
        req.setAttribute("commentData", comments);
        return "post/detail";
    }

    /**
     * 查找当前用户是否收藏了当前查看的文章
     * @param pid 文章id
     * @return 前端需要的是collection = true 或者false来判断是否收藏
     */
    @ResponseBody
    @PostMapping("/collection/find")
    public Result collectionFind(Long pid) {
        int count = collectionService.count(new QueryWrapper<MUserCollection>()
                .eq("user_id", getProfile().getId())
                .eq("post_id", pid)
        );
        return Result.success(MapUtil.of("collection", count > 0));
    }


    /**
     * 收藏文章
     * @param pid
     * @return
     */
    @ResponseBody
    @PostMapping("/collection/add/")
    public Result collectionRemove(Long pid) {
        //判断文章是否存在
        MPost post = postService.getById(pid);
        Assert.isTrue(post != null, "该帖子已经被删除!");
        //判断文章是否已经收藏
        int count = collectionService.count(new QueryWrapper<MUserCollection>()
                .eq("user_id", getProfile().getId())
                .eq("post_id", pid)
        );
        if(count > 0) {
            return Result.fail("该文章已收藏!");
        }
        MUserCollection collection = new MUserCollection();
        collection.setPostId(pid);
        collection.setPostUserId(post.getUserId());
        collection.setUserId(getProfile().getId());
        collection.setCreated(new Date());
        collection.setModified(new Date());

        boolean save = collectionService.save(collection);
        return save ? Result.success("收藏成功", null) : Result.fail("收藏失败");
    }
    /**
     * 取消收藏
     * @param pid
     * @return
     */
    @ResponseBody
    @PostMapping("/collection/remove/")
    public Result collectionAdd(Long pid) {
        //判断文章是否存在
        MPost post = postService.getById(pid);
        Assert.isTrue(post != null, "该帖子已经被删除!");
        boolean remove = collectionService.remove(new QueryWrapper<MUserCollection>()
                .eq("user_id", getProfile().getId())
                .eq("post_id", pid)
        );
        return remove ? Result.success("取消收藏成功", null) : Result.fail("取消收藏失败");
    }

    @GetMapping("/post/edit")
    public String postEdit() {
        /**
         * 从http请求链接获取参数判断，存在id,则是编辑文章， 不存在id, 则是发布文章
         * 编辑： http://localhost:8080/postDetail/id --> 可获取id
         * 发布： http://localhost:8080/post/edit     --> 没有携带id
         */
        String id = req.getParameter("id");
        if(!StringUtils.isEmpty(id)) {
            MPost post = postService.getById(id);
            /**
             * 反着来
             * isTrue(boolean expression) / isTrue(boolean expression, String message)
             * 当 expression 不为 true 抛出异常；
             */
            Assert.isTrue(post != null, "该文章已经删除！");
            Assert.isTrue(post.getUserId().longValue() == getProfile().getId().longValue(), "没有权限编辑此文章");
            req.setAttribute("post", post);
        }
        req.setAttribute("categories", categoryService.list());
        return "post/edit";
    }

    /**
     * 发布、编辑文章
     * @param post
     * @return
     */
    @ResponseBody
    @PostMapping("/post/submit")
    public Result submit(MPost post) {
        //检验post实体信息
        ValidationUtil.ValidResult validResult = ValidationUtil.validateBean(post);
        if(validResult.hasErrors()) {
            return Result.fail(validResult.getErrors());
        }
        //发布文章
        if(post.getId() == null) {
            post.setUserId(getProfile().getId());
            post.setModified(new Date());
            post.setCreated(new Date());
            post.setCommentCount(0);
            post.setEditMode(null);
            post.setLevel(0);
            post.setRecommend(false);
            post.setViewCount(0);
            post.setVoteDown(0);
            post.setVoteUp(0);
            postService.save(post);

        } else {
            //编辑文章
            MPost tempPost = postService.getById(post.getId());
            Assert.isTrue(tempPost.getUserId().longValue() == getProfile().getId().longValue(), "无权限编辑此文章！");
            tempPost.setTitle(post.getTitle());
            tempPost.setContent(post.getContent());
            tempPost.setCategoryId(post.getCategoryId());
            postService.updateById(tempPost);
        }

        // 通知消息给mq，告知更新或添加
        amqpTemplate.convertAndSend(
                RabbitConfig.ES_EXCHANGE,
                RabbitConfig.ES_BIND_KEY,
                new PostMqIndexMessage(post.getId(), PostMqIndexMessage.CREATE_OR_UPDATE) //发送的内容
        );
        return Result.success("发布成功", null).action("/postDetail/" + post.getId());
    }

    @ResponseBody
    @Transactional
    @PostMapping("/post/delete/")
    public Result deletePost(Long id) {
        MPost post = postService.getById(id);
        if(post == null) {
            return Result.fail("该文章已经被删除!");
        }
        Assert.isTrue(post.getUserId().longValue() == getProfile().getId().longValue(), "无权限删除此文章！");
        postService.removeById(id);
        // 删除相关消息、收藏等
        messageService.removeByMap(MapUtil.of("post_id", id));
        collectionService.removeByMap(MapUtil.of("post_id", id));
        //如果是本周发布的文章的话，需要删除缓存，并重新对本周热议内容做并集
        //day:rank:20221109
        String dayRank = RedisConstants.DAY_RANK + DateUtil.format(post.getCreated(), DatePattern.PURE_DATE_FORMAT);
        //查找redis的zset中元素的下标，不存在返回null
        Long rank = redisTemplate.opsForZSet().rank(dayRank, id);
        if(rank != null) {
            redisTemplate.opsForZSet().remove(dayRank,id);
        }
        boolean b = redisUtil.hasKey(RedisConstants.RANK_POST+id);
        if(b) {
            redisUtil.del(RedisConstants.RANK_POST+id);
        }
        // 本周热议重新做并集
        postService.zUnionAndStoreLast7DayForWeekRank();

        // 通知消息给mq，告知更新或添加
        amqpTemplate.convertAndSend(
                RabbitConfig.ES_EXCHANGE,
                RabbitConfig.ES_BIND_KEY,
                new PostMqIndexMessage(post.getId(), PostMqIndexMessage.REMOVE) //发送的内容
        );
        return Result.success().action("/index");

    }

    @ResponseBody
    @Transactional
    @PostMapping("/post/reply/")
    public Result reply(Long jid, String content) {
        Assert.notNull(jid, "找不到对应的文章");
        Assert.hasLength(content, "评论内容不能为空");
        MPost post = postService.getById(jid);
        Assert.isTrue(post != null, "该文章已被删除");
        MComment comment = new MComment();
        comment.setPostId(jid);
        comment.setContent(content);
        comment.setUserId(getProfile().getId());
        comment.setCreated(new Date());
        comment.setModified(new Date());
        comment.setLevel(0);
        comment.setVoteDown(0);
        comment.setVoteUp(0);
        commentService.save(comment);

        // 评论数量加一
        post.setCommentCount(post.getCommentCount() + 1);
        postService.updateById(post);

        // 本周热议数量加一
        postService.incrCommentCountAndUnionForWeekRank(post.getId(), true);

        // 通知作者，有人评论了你的文章
        // 作者自己评论自己文章，不需要通知
        if(comment.getUserId() != post.getUserId()) {
            MUserMessage message = new MUserMessage();
            message.setPostId(jid);
            message.setCommentId(comment.getId());
            message.setFromUserId(getProfile().getId());
            message.setToUserId(post.getUserId());
            message.setType(1);
            message.setContent(content);
            message.setCreated(new Date());
            message.setStatus(0);
            messageService.save(message);

            // 即时通知作者（websocket）
            webSocketService.sendMessCountToUser(message.getToUserId());
        }

        // 通知被@的人，有人回复了你的文章
        if(content.startsWith("@")) {
            String username = content.substring(1, content.indexOf(" "));
            System.out.println(username);

            MUser user = userService.getOne(new QueryWrapper<MUser>().eq("username", username));
            if(user != null) {
                MUserMessage message = new MUserMessage();
                message.setPostId(jid);
                message.setCommentId(comment.getId());
                message.setFromUserId(getProfile().getId());
                message.setToUserId(user.getId());
                message.setType(2);
                message.setContent(content);
                message.setCreated(new Date());
                message.setStatus(0);
                messageService.save(message);

                // 即时通知被@的用户
            }
        }
        return Result.success().action("/postDetail/" + post.getId());
    }

    /**
     * 删除评论
     * @param id
     * @return
     */
    @ResponseBody
    @Transactional
    @PostMapping("/post/jieda-delete/")
    public Result reply(Long id) {

        Assert.notNull(id, "评论id不能为空！");

        MComment comment = commentService.getById(id);

        Assert.notNull(comment, "找不到对应评论！");

        if(!comment.getUserId().equals((getProfile().getId()))) {
            return Result.fail("不是你发表的评论！");
        }
        commentService.removeById(id);

        // 评论数量减一
        MPost post = postService.getById(comment.getPostId());
        post.setCommentCount(post.getCommentCount() - 1);
        postService.saveOrUpdate(post);

        //评论数量减一
        postService.incrCommentCountAndUnionForWeekRank(comment.getPostId(), false);

        return Result.success(null);
    }
}
